package es.us.lsi.daw.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.TimeZone;

import javax.servlet.http.HttpSession;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import es.us.lsi.daw.annotations.Busqueda;
import es.us.lsi.daw.model.security.User;
import es.us.lsi.daw.model.util.BaseEntity;




public abstract class Util {

	public static int		L_V			= 0;
	public static int		L_S			= 1;
	public static int		L_D			= 2;
	public static String	NUMEROS		= "0123456789";
	public static String	MAYUSCULAS	= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	public static String	MINUSCULAS	= "abcdefghijklmnopqrstuvwxyz";
	
	public static String convertFromUTF8(String s) {

		String out = null;
		try {
			out = new String(s.getBytes("ISO-8859-1"), "UTF-8");
		} catch (java.io.UnsupportedEncodingException e) {
			return null;
		}
		return out;
	}

	/* convert from internal Java String Format -> UTF-8 encoded HTML/JSP-Pages */
	public static String convertToUTF8(String s) {

		String out = null;
		try {
			out = new String(s.getBytes("UTF-8"));
		} catch (java.io.UnsupportedEncodingException e) {
			return null;
		}
		return out;
	}

	public static <T> String serializar(T objeto) {

		ByteArrayOutputStream arrayStrem = new ByteArrayOutputStream();
		ObjectOutputStream salida;
		try {

			salida = new ObjectOutputStream(arrayStrem);
			salida.writeObject(objeto);
		} catch (IOException e) {
			e.printStackTrace();
			return "";
		}

		return Base64.encodeBase64URLSafeString(arrayStrem.toByteArray());

	}

	@SuppressWarnings("unchecked")
	public static <T> T desSerializar(String objeto) {

		ByteArrayInputStream arrayStrem;
		if (!objeto.isEmpty()) {
			arrayStrem = new ByteArrayInputStream(Base64.decodeBase64(objeto.getBytes()));
		} else {
			return null;
		}

		ObjectInputStream entrada = null;
		T result = null;
		try {

			entrada = new ObjectInputStream(arrayStrem);
			result = (T) entrada.readObject();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		}

		return result;
	}

	@SuppressWarnings("unchecked")
	public static void ordenaAscendente(List lstLista, final String propiedad) {

		if (lstLista != null) {
			Collections.sort(lstLista, new Comparator() {

				public int compare(Object obj1, Object obj2) {

					Class clase = obj1.getClass();
					String getter = "get" + Character.toUpperCase(propiedad.charAt(0)) + propiedad.substring(1);
					try {
						Method getPropiedad = clase.getMethod(getter);

						Object propiedad1 = getPropiedad.invoke(obj1);
						Object propiedad2 = getPropiedad.invoke(obj2);

						if (propiedad1 instanceof Comparable && propiedad2 instanceof Comparable) {
							Comparable prop1 = (Comparable) propiedad1;
							Comparable prop2 = (Comparable) propiedad2;
							return prop1.compareTo(prop2);
						}// CASO DE QUE NO SEA COMPARABLE
						else {
							if (propiedad1.equals(propiedad2))
								return 0;
							else
								return 1;

						}

					} catch (Exception e) {
						e.printStackTrace();
					}
					return 0;
				}
			});
		}

	}

	@SuppressWarnings("unchecked")
	public static void ordenaDescendente(List lstLista, final String propiedad) {

		if (lstLista != null) {
			Collections.sort(lstLista, new Comparator() {

				public int compare(Object obj1, Object obj2) {

					Class clase = obj1.getClass();
					String getter = "get" + Character.toUpperCase(propiedad.charAt(0)) + propiedad.substring(1);
					try {
						Method getPropiedad = clase.getMethod(getter);

						Object propiedad1 = getPropiedad.invoke(obj1);
						Object propiedad2 = getPropiedad.invoke(obj2);

						if (propiedad1 instanceof Comparable && propiedad2 instanceof Comparable) {
							Comparable prop1 = (Comparable) propiedad1;
							Comparable prop2 = (Comparable) propiedad2;
							return (prop1.compareTo(prop2) * -1);
						}// CASO DE QUE NO SEA COMPARABLE
						else {
							if (propiedad1.equals(propiedad2))
								return 0;
							else
								return 1;

						}

					} catch (Exception e) {
						e.printStackTrace();
					}
					return 0;
				}
			});
		}

	}

	public static String formatearFecha(Date fecha) {

		return new SimpleDateFormat("dd/MM/yyyy").format(fecha);
	}

	public static String formatearHora(Date fecha) {

		DateFormat fmtFch = new SimpleDateFormat("HH:mm");
		fmtFch.setTimeZone(TimeZone.getTimeZone("Europe/Madrid"));
		return fmtFch.format(fecha);
	}

	public static boolean esEntero(String num) {

		try {
			Integer.parseInt(num);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	public static boolean esLong(String num) {

		try {
			new Long(num);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	/**
	 * Establece un valor a un campo.
	 * 
	 * @param obj
	 *            Objeto al que se desea establecer dicha propiedad.
	 * @param campo
	 *            Propiedad del objeto donde se almacenara el valor.
	 * @param valor
	 *            Contenido que va a ser almacenado en la propiedad.
	 */
	public static void establecerValorCampoPorReflexion(Object obj, String campo, Object valor) {

		try {
			Class c = obj.getClass();
			Field f;
			f = obtenerCampoClaseSuperClases(c, campo);// c.getDeclaredField(campo);

			if (f != null) {
				f.setAccessible(true);
				f.set(obj, valor);
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Obtiene el valor de una determinada propiedad de un objeto.
	 * 
	 * @param campo
	 *            Nombre de la propiedad de la que se quiere obtener el valor.
	 * @param obj
	 *            Objeto del que se desea obtener el valor.
	 * @return Devuelve el valor del campo del objeto recibido por parámetro.
	 */
	public static Object obtenerValorCampo(String campo, Object obj) {

		try {
			Field f = null;
			try {
				f = obj.getClass().getDeclaredField(campo);
			} catch (Exception e) {}
			if (f == null && obj.getClass().getSuperclass() != null)
				f = obj.getClass().getSuperclass().getDeclaredField(campo);
			if (f != null) {
				f.setAccessible(true);
				return f.get(obj);
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static List<Long> obtenerIdentificadoresString(String cad, String split) {

		List<Long> lstIdentificadores = new ArrayList<Long>();
		try {
			for (String l : cad.split(split)) {
				if (!l.isEmpty())
					lstIdentificadores.add(new Long(l));
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
		return lstIdentificadores;
	}

	public static List<Field> obtenerCamposClaseSuperClases(Class c) {

		int sw = 0;
		Class aux = c;
		List<Field> lstCampos = new ArrayList<Field>();
		while (sw == 0) {
			for (Field f : aux.getDeclaredFields())
				lstCampos.add(f);
			if (aux.getSuperclass() != null)
				aux = aux.getSuperclass();
			else
				sw = 1;
		}

		return lstCampos;
	}

	public static Field obtenerCampoClaseSuperClases(Class c, String nombreCampo) {

		int sw = 0;
		Class aux = c;
		Field campo = null;
		try {
			while (sw == 0) {
				for (Field f : aux.getDeclaredFields()) {
					if (f.getName().equals(nombreCampo)) {
						campo = f;
						campo.setAccessible(true);
						sw = 1;
					}
				}
				if (aux.getSuperclass() != null)
					aux = aux.getSuperclass();
				else
					sw = 1;
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		return campo;
	}

	/**
	 * Obtener las propiedades sobre las que se va a permitir efectuar una busqueda.
	 * 
	 * @param clase
	 *            Se trata de la clase a la que pertenece el objeto del cual se quiere identificar las propiedades sobre
	 *            las que se permiten hacer busquedas.
	 * @return Devuelve una lista con el nombre de todas las propiedades de una clase sobre las que se permiten hacer
	 *         búsquedas.
	 */
	public static List<String> obtenerCamposBusqueda(Class clase) {

		List<String> lstCamposBusqueda = new ArrayList<String>();
		for (Field f : clase.getDeclaredFields()) {
			if (f.isAnnotationPresent(Busqueda.class))
				lstCamposBusqueda.add(f.getName());
		}
		if (clase.getSuperclass() != null) {
			for (Field f : clase.getSuperclass().getDeclaredFields()) {
				if (f.isAnnotationPresent(Busqueda.class))
					lstCamposBusqueda.add(f.getName());
			}
		}
		return lstCamposBusqueda;
	}

	public static String generarCadenaBusqueda(List elementos) {

		Class clase = null;
		String dato = "";
		if (elementos != null && elementos.size() > 0)
			clase = elementos.get(0).getClass();
		if (clase != null) {
			// Obtenemos los nombres de las propiedades sobre las que
			// se están realizando la búsqueda.
			List<String> lstCamposBusqueda = obtenerCamposBusqueda(clase);
			if (lstCamposBusqueda != null) {
				for (Object o : elementos) {
					int cont = 0; // Indica el índice del elemento actual.
					// Generamos una cadena que contiene el valor de los
					// campos, sobre los que se realizan las búsquedas,
					// separados por punto y coma.
					// Ejemplo:
					// Propiedad1;Propiedad2....
					if (!dato.isEmpty())
						dato += ", ";
					for (String campo : lstCamposBusqueda) {
						if (lstCamposBusqueda.size() > 1 && cont > 0)
							dato += ";" + obtenerValorCampo(campo, o);
						else
							dato += obtenerValorCampo(campo, o);
						cont++;
					}
				}
			}
		}
		return dato;
	}

	public static String generarCadenaBusqueda(Object elemento) {

		if (elemento != null) {
			List lstElementos = new ArrayList<Object>();
			lstElementos.add(elemento);
			return generarCadenaBusqueda(lstElementos);
		} else
			return "";
	}

	@SuppressWarnings("unchecked")
	public static List<Class> getClasses(String packageName) throws ClassNotFoundException, IOException {

		try {
			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			assert classLoader != null;
			String path = packageName.replace('.', '/');
			Enumeration<URL> nmrResources = classLoader.getResources(path);
			List<File> lstDirs = new ArrayList<File>();
			while (nmrResources.hasMoreElements()) {
				URL resource = nmrResources.nextElement();
				String fileName = resource.getFile();
				String fileNameDecoded = URLDecoder.decode(fileName, "UTF-8");
				lstDirs.add(new File(fileNameDecoded));
			}
			ArrayList<Class> classes = new ArrayList<Class>();
			for (File directory : lstDirs) {
				classes.addAll(findClasses(directory, packageName));
			}
			return classes;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public static Class obtenerClase(String packageName, String clase) throws ClassNotFoundException, IOException {

		try {
			Class c = null;
			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			assert classLoader != null;
			String path = packageName.replace('.', '/');
			Enumeration<URL> nmrResources = classLoader.getResources(path);
			List<File> lstDirs = new ArrayList<File>();
			while (nmrResources.hasMoreElements()) {
				URL resource = nmrResources.nextElement();
				String fileName = resource.getFile();
				String fileNameDecoded = URLDecoder.decode(fileName, "UTF-8");
				lstDirs.add(new File(fileNameDecoded));
			}
			for (File directory : lstDirs) {
				c = buscaClase(directory, packageName, clase);
			}
			return c;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Método recursivo para buscar todas las clases de un determinado directorio y sus respectivos subdirectorios.
	 * 
	 * @param directory
	 *            Directorio principal
	 * @param packageName
	 *            Nombre del paquete donde se desea realizar la búsqueda de la clase.
	 * @return Las clases encontradas, o en caso de no encontrar ninguna, devuelve una lista vacia.
	 * @throws ClassNotFoundException
	 */
	@SuppressWarnings("unchecked")
	private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {

		List<Class> lstClasses = new ArrayList<Class>();
		if (!directory.exists()) {
			return lstClasses;
		}
		File[] files = directory.listFiles();
		for (File file : files) {
			String fileName = file.getName();
			if (file.isDirectory()) {
				assert !fileName.contains(".");
				lstClasses.addAll(findClasses(file, packageName + "." + fileName));
			} else if (fileName.endsWith(".class") && !fileName.contains("$")) {
				Class _class;
				try {
					_class = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6));
				} catch (ExceptionInInitializerError e) {
					_class = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6), false, Thread.currentThread().getContextClassLoader());
				}
				lstClasses.add(_class);
			}
		}
		return lstClasses;
	}

	/**
	 * Método recursivo para buscar una clase en un determinado directorio y sus respectivos subdirectorios.
	 * 
	 * @param directory
	 *            Directorio principal
	 * @param packageName
	 *            Nombre del paquete donde se desea realizar la búsqueda de la clase.
	 * @param clase
	 *            Nombre de la clase a buscar.
	 * @return La clase encontrada, o en caso de no encontrar ninguna, devuelve un valor nulo.
	 * @throws ClassNotFoundException
	 */
	@SuppressWarnings("unchecked")
	private static Class buscaClase(File directory, String packageName, String clase) throws ClassNotFoundException {

		Class c = null;
		// List<Class> classes = new ArrayList<Class>();
		if (!directory.exists()) {
			return null;
		}
		File[] files = directory.listFiles();
		for (File file : files) {
			String fileName = file.getName();
			if (file.isDirectory() && c == null) {
				assert !fileName.contains(".");
				c = buscaClase(file, packageName + "." + fileName, clase);
			} else if (fileName.endsWith(".class") && !fileName.contains("$") && c == null) {
				Class _class;
				try {
					_class = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6));
				} catch (ExceptionInInitializerError e) {
					_class = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6), false, Thread.currentThread().getContextClassLoader());
				}
				if (_class.getSimpleName().equals(clase))
					c = _class;
			}
		}
		return c;
	}

	public static int obtenerDiasEntreFechas(Date fechaInicio, Date fechaFinal) {

		Calendar cldInicio = Calendar.getInstance();
		Calendar cldFin = Calendar.getInstance();

		cldInicio.setTime(fechaInicio);
		cldFin.setTime(fechaFinal);
		int dias = 0;

		if (cldInicio.get(Calendar.YEAR) < cldFin.get(Calendar.YEAR)) {
			int diasAnio = 0;

			while (cldInicio.get(Calendar.YEAR) < cldFin.get(Calendar.YEAR)) {
				diasAnio += cldInicio.getActualMaximum(Calendar.DAY_OF_YEAR);
				cldInicio.add(Calendar.YEAR, 1);
			}
			dias = (diasAnio + cldFin.get(Calendar.DAY_OF_YEAR)) - cldInicio.get(Calendar.DAY_OF_YEAR);
		} else
			dias = cldFin.get(Calendar.DAY_OF_YEAR) - cldInicio.get(Calendar.DAY_OF_YEAR);

		return dias;
	}

	public static boolean esFechaPosterior(String fechaInicio, String fechaFin) {

		DateFormat fmtFch = new SimpleDateFormat("dd/MM/yyyy");
		try {
			Date fechaInicioAux = fmtFch.parse(fechaInicio);
			Date fechaFinAux = fmtFch.parse(fechaFin);
			return esFechaPosterior(fechaInicioAux, fechaFinAux);
		} catch (ParseException e) {
			e.printStackTrace();
			return false;
		}
	}

	public static boolean esFechaPosteriorIgual(Date fechaInicio, Date fechaFin) {

		if (fechaInicio == null || fechaFin == null)
			return false;
		else
			return (fechaInicio.before(fechaFin) || fechaInicio.equals(fechaFin));
	}

	public static boolean esFechaPosteriorIgual(String fechaInicio, String fechaFin) {

		DateFormat fmtFch = new SimpleDateFormat("dd/MM/yyyy");
		try {
			Date fechaInicioAux = fmtFch.parse(fechaInicio);
			Date fechaFinAux = fmtFch.parse(fechaFin);
			return esFechaPosteriorIgual(fechaInicioAux, fechaFinAux);
		} catch (ParseException e) {
			e.printStackTrace();
			return false;
		}
	}

	public static boolean esFechaPosterior(Date fechaInicio, Date fechaFin) {

		if (fechaInicio == null || fechaFin == null)
			return false;
		else
			return !(fechaInicio.compareTo(fechaFin) > 0);
	}

	public static boolean tieneClase(Object o, Class c) {

		int sw = 0;
		Class aux = o.getClass();
		while (sw == 0) {
			if (aux.equals(c))
				return true;
			else {
				if (aux.getSuperclass() != null)
					aux = aux.getSuperclass();
				else
					sw = 1;
			}
		}
		return false;
	}

	public static User obtenerUsuarioSesion() {

		User usuario = null;
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		if (auth != null && auth.getPrincipal() != null) {
			usuario = (User) auth.getPrincipal();
		}
		return usuario;
	}

	public static ModelMap paginarIntervaloFechas(Date fechaInicio, Date fechaFin, int dias, Integer pagina) {

		return paginarIntervaloFechas(fechaInicio, fechaFin, dias, pagina, null);
	}

	public static ModelMap paginarIntervaloFechas(Date fechaInicio, Date fechaFin, int dias, Integer pagina, Integer tipoIntervalo) {

		ModelMap mapa = new ModelMap();
		if (fechaInicio != null && fechaFin != null) {
			Calendar cldInicio = Calendar.getInstance();
			Calendar cldFin = Calendar.getInstance();
			int diasEntreFechas = obtenerDiasEntreFechas(fechaInicio, fechaFin) + 1;
			if (diasEntreFechas > dias) {
				int numPagina;
				int totalPages;
				int i;
				int tam;
				if (pagina == null)
					numPagina = 1;
				else
					numPagina = pagina;
				tam = diasEntreFechas;

				i = tam / dias;
				if (tam % dias != 0)
					i++;
				totalPages = i;
				if (numPagina > totalPages)
					numPagina = totalPages;
				mapa.put("totalPages", totalPages);
				mapa.put("pagina", numPagina);

				int diaInicio = dias * (numPagina - 1);
				cldInicio.setTime(fechaInicio);
				cldInicio.add(Calendar.DATE, diaInicio);
				if ((diaInicio + dias) <= diasEntreFechas) {
					cldFin.setTime(cldInicio.getTime());
					cldFin.add(Calendar.DATE, (dias - 1));
				} else {
					cldFin.setTime(fechaFin);
				}
			} else {
				cldInicio.setTime(fechaInicio);
				cldFin.setTime(fechaFin);
			}
			mapa.addAttribute("inicio", cldInicio);
			mapa.addAttribute("fin", cldFin);
			mapa.addAttribute("inicioSemana", Util.formatearFecha(cldInicio.getTime()));
			Calendar cldFinAux = Calendar.getInstance();
			cldFinAux.setTime(cldInicio.getTime());
			if (tipoIntervalo == null)
				cldFinAux.setTime(cldFin.getTime());
			else if (tipoIntervalo == Util.L_V)// De lunes a viernes
				cldFinAux.add(Calendar.DATE, 4);
			else if (tipoIntervalo == Util.L_S)
				cldFinAux.add(Calendar.DATE, 5);// De lunes a sabado
			else if (tipoIntervalo == Util.L_D)
				cldFinAux.add(Calendar.DATE, 6);// De lunes a domingo
			mapa.addAttribute("finSemana", Util.formatearFecha(cldFinAux.getTime()));
		}
		return mapa;
	}

	public static String obtenerDiaSemana(int dia) {

		String[] dias = {"Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"};
		if (dia < dias.length)
			return dias[dia];
		else
			return null;
	}

	public static String obtenerCronDesdeFechaHora(String fecha, String hora) {

		String patronFecha = "([0-2][0-9]|30|31)/(0[0-9]|10|11|12)/([0-9][0-9][0-9][0-9])";
		String patronHora = "(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]";
		if (fecha != null && !fecha.isEmpty() && fecha.matches(patronFecha)) {
			if (hora != null && !hora.isEmpty() && hora.matches(patronHora)) {
				String cron = "0 ";
				String[] arrayFecha = fecha.split("/");
				String[] arrayHora = hora.split(":");
				String dia = arrayFecha[0];
				String mes = arrayFecha[1];
				String anio = arrayFecha[2];
				String horaAux = arrayHora[0];
				String minutosAux = arrayHora[1];
				if (minutosAux.indexOf("0") == 0)
					minutosAux = minutosAux.substring(1);
				if (horaAux.indexOf("0") == 0)
					horaAux = horaAux.substring(1);
				if (dia.indexOf("0") == 0)
					dia = dia.substring(1);
				if (mes.indexOf("0") == 0)
					mes = mes.substring(1);

				cron += minutosAux;
				cron += " " + horaAux;
				cron += " " + dia;
				cron += " " + mes;
				cron += " ? " + anio;
				return cron;
			}
		}
		return null;
	}

	public static void inicializaCalendario(Calendar cldFecha) {

		cldFecha.set(Calendar.HOUR_OF_DAY, 0);
		cldFecha.set(Calendar.MINUTE, 0);
		cldFecha.set(Calendar.SECOND, 0);
		cldFecha.set(Calendar.MILLISECOND, 0);
	}

	public static void inicializaCalendariosSemana(Calendar cldInicio, Calendar cldFin, boolean siguiente) {

		cldInicio.set(Calendar.HOUR_OF_DAY, 0);
		cldInicio.set(Calendar.MINUTE, 0);
		cldInicio.set(Calendar.SECOND, 0);
		if (siguiente)
			cldInicio.add(Calendar.DATE, 7);
		if (!Util.obtenerDiaSemana(cldInicio.get(Calendar.DAY_OF_WEEK) - 1).equals("Lunes")) {
			cldInicio.add(Calendar.DATE, -1);
			boolean sw = true;
			while (sw) {
				if (!Util.obtenerDiaSemana(cldInicio.get(Calendar.DAY_OF_WEEK) - 1).equals("Lunes"))
					cldInicio.add(Calendar.DATE, -1);
				else
					sw = false;
			}
		}
		cldFin.setTime(cldInicio.getTime());
		cldFin.set(Calendar.HOUR_OF_DAY, 0);
		cldFin.set(Calendar.MINUTE, 0);
		cldFin.set(Calendar.SECOND, 0);
		cldFin.add(Calendar.DATE, 6);

	}

	public static void establecerLunesSemanaActual(Calendar cldInicio) {

		cldInicio.set(Calendar.HOUR_OF_DAY, 0);
		cldInicio.set(Calendar.MINUTE, 0);
		cldInicio.set(Calendar.SECOND, 0);
		if (!Util.obtenerDiaSemana(cldInicio.get(Calendar.DAY_OF_WEEK) - 1).equals("Lunes")) {
			cldInicio.add(Calendar.DATE, -1);
			boolean sw = true;
			while (sw) {
				if (!Util.obtenerDiaSemana(cldInicio.get(Calendar.DAY_OF_WEEK) - 1).equals("Lunes"))
					cldInicio.add(Calendar.DATE, -1);
				else
					sw = false;
			}
		}
	}

	public static List<Long> obtenerIdentificadoresListaObjetos(List lstObjetos) {

		List<Long> lstIdentificadores = new ArrayList<Long>();
		if (lstObjetos != null && !lstObjetos.isEmpty()) {
			for (Object o : lstObjetos) {
				if (o.getClass().getSuperclass() != null && o.getClass().getSuperclass().equals(BaseEntity.class)) {
					if (((BaseEntity) o).getId() != null)
						lstIdentificadores.add(((BaseEntity) o).getId());
				}
			}
		}
		return lstIdentificadores;
	}

	public static Date obtenerFechaDesdeCadena(String fechaCadena) {

		if (fechaCadena != null && !fechaCadena.isEmpty()) {
			DateFormat fmtFch = new SimpleDateFormat("dd/MM/yyyy");
			Date fecha;
			try {
				fecha = fmtFch.parse(fechaCadena);
			} catch (ParseException e) {
				e.printStackTrace();
				return null;
			}
			return fecha;
		}
		return null;
	}

	public static Calendar obtenerCalendarDesdeCadena(String fechaCadena) {

		if (fechaCadena != null && !fechaCadena.isEmpty()) {
			Calendar cldFecha = Calendar.getInstance();
			inicializaCalendario(cldFecha);
			Date fechaAux = obtenerFechaDesdeCadena(fechaCadena);
			if (fechaAux != null) {
				cldFecha.setTime(fechaAux);
				return cldFecha;
			}
		}
		return null;
	}

	public static String getPassword() {

		return getPassword(MAYUSCULAS + MINUSCULAS, 8);
	}

	public static String getPassword(int tam) {

		return getPassword(MAYUSCULAS + MINUSCULAS, tam);
	}

	public static <T> void eliminarNullOVacio(List<T> lstProcesar) {

		for (int i = 0; i < lstProcesar.size(); i++) {
			Object obj = lstProcesar.get(i);

			if (obj == null || obj == "") {
				lstProcesar.remove(i);
				i--;
			}
		}
	}

	public static String encriptarPassword(String password) {

		return encriptarPassword(password, "SHA1");
	}

	public static String encriptarPassword(String password, String method) {

		MessageDigest md = null;
		byte[] buffer, digest;
		String hash = "";

		try {
			buffer = password.getBytes();
			md = MessageDigest.getInstance(method);
			md.update(buffer);
			digest = md.digest();

			for (byte aux : digest) {
				int b = aux & 0xff;
				if (Integer.toHexString(b).length() == 1)
					hash += "0";
				hash += Integer.toHexString(b);
			}
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

		return hash;
	}

	private static String getPassword(String key, int length) {

		String pswd = "";

		for (int i = 0; i < length; i++) {
			pswd += (key.charAt((int) (Math.random() * key.length())));
		}

		return pswd;
	}

	/**
	 * Obtiene el valor de una determinada propiedad de un objeto.
	 * 
	 * @param campo
	 *            Nombre de la propiedad de la que se quiere obtener el valor.
	 * @param obj
	 *            Objeto del que se desea obtener el valor.
	 * @return Devuelve el valor del campo del objeto recibido por parámetro.
	 */
	public static Object obtenerValorMetodoParaTabla(String metodo, Object obj) {

		try {
			DateFormat dfDate = new SimpleDateFormat("dd/MM/yyyy");
			Method method = null;
			Object result = null;
			try {
				method = obj.getClass().getDeclaredMethod(metodo);
			} catch (Exception e) {}
			if (method == null && obj.getClass().getSuperclass() != null)
				method = obj.getClass().getSuperclass().getDeclaredMethod(metodo);
			if (method != null) {
				method.setAccessible(true);
				result = method.invoke(obj, new Object[0]);
				if (result != null) {
					if (result instanceof Date) {
						result = dfDate.format(result);
					} else if (result instanceof Calendar) {
						result = dfDate.format(((Calendar) result).getTime());
					}
				}

				if (result == null) {
					result = "";
				}
				return result;
			}
		} catch (SecurityException e) {
			LoggerFactory.getLogger(Util.class).error("error", e);
		} catch (IllegalArgumentException e) {
			LoggerFactory.getLogger(Util.class).error("error", e);
		} catch (IllegalAccessException e) {
			LoggerFactory.getLogger(Util.class).error("error", e);
		} catch (InvocationTargetException e) {
			LoggerFactory.getLogger(Util.class).error("error", e);
		} catch (NoSuchMethodException e) {
			LoggerFactory.getLogger(Util.class).error("error", e);
		}
		return "";
	}

	/**
	 * Obtiene el valor de una determinada propiedad de un objeto.
	 * 
	 * @param campo
	 *            Nombre de la propiedad de la que se quiere obtener el valor.
	 * @param obj
	 *            Objeto del que se desea obtener el valor.
	 * @return Devuelve el valor del campo del objeto recibido por parámetro.
	 */
	public static Object obtenerValorCampoParaTabla(String campo, Object obj) {

		try {
			DateFormat dfDate = new SimpleDateFormat("dd/MM/yyyy");
			Field f = null;
			Object result = null;
			String[] fieldNavigation = null;

			fieldNavigation = campo.split("\\.");
			for (String field : fieldNavigation) {
				try {
					f = obj.getClass().getDeclaredField(field);
				} catch (Exception e) {}
				if (f == null && obj.getClass().getSuperclass() != null) {
					f = obj.getClass().getSuperclass().getDeclaredField(field);
				}
				if (f != null) {
					f.setAccessible(true);
					obj = f.get(obj);
				}
			}

			if (obj != null) {
				result = obj;
				if (result != null) {
					if (result instanceof Date) {
						result = dfDate.format(result);
					} else if (result instanceof Calendar) {
						result = dfDate.format(((Calendar) result).getTime());
					}
				}

				if (result == null) {
					result = "";
				}
				return result;
			}
		} catch (SecurityException e) {
			LoggerFactory.getLogger(Util.class).error("error", e);
		} catch (NoSuchFieldException e) {
			LoggerFactory.getLogger(Util.class).error("error", e);
		} catch (IllegalArgumentException e) {
			LoggerFactory.getLogger(Util.class).error("error", e);
		} catch (IllegalAccessException e) {
			LoggerFactory.getLogger(Util.class).error("error", e);
		}
		return "";
	}
	
	public static String shuffleString(String string)
	{
	  List<String> letters = Arrays.asList(string.split(""));
	  Collections.shuffle(letters);
	  String shuffled = "";
	  for (String letter : letters) {
	    shuffled += letter;
	  }
	  return shuffled;
	}
	
	public static HttpSession getSessionFromContext() {

        try {
                return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession();
        } catch (Exception e) {
                e.printStackTrace();
                return null;
        }
	}

}
